package com.zx.idc.backend.gui.api.management.infosecurity.violationwebsite.management.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.google.common.collect.Lists;
import com.zx.idc.backend.gui.api.commom.entity.UploadModel;
import com.zx.idc.backend.gui.api.commom.template.NIdcFtpTemplate;
import com.zx.idc.backend.gui.api.management.infosecurity.violationwebsite.management.service.IllegalWebService;
import com.zx.idc.cache.entity.IllegalSiteMetaInfo;
import com.zx.idc.cache.slog.SlogIllegalSiteCacheService;
import com.zx.idc.common.attributes.FTPReportDataTypeEnum;
import com.zx.idc.common.attributes.NetCommunicationFileTypeEnum;
import com.zx.idc.common.attributes.SchemaFileNameEnum;
import com.zx.idc.common.lang.ListUtil;
import com.zx.idc.common.util.LocalDateTimeFormatUtil;
import com.zx.idc.ds.base.house.entity.BaseHouseInfo;
import com.zx.idc.ds.base.house.service.IBaseHouseInfoService;
import com.zx.idc.ds.base.oper.entity.BaseOperCompany;
import com.zx.idc.ds.base.oper.service.IBaseOperCompanyService;
import com.zx.idc.ds.common.constant.ReportStatusConstant;
import com.zx.idc.ds.slog.entity.HandleEntity;
import com.zx.idc.ds.slog.entity.SlogIllegalSite;
import com.zx.idc.ds.slog.entity.SlogIllegalSiteLog;
import com.zx.idc.ds.slog.service.ISlogIllegalSiteLogService;
import com.zx.idc.ds.slog.service.ISlogIllegalSiteService;
import com.zx.idc.ds.slog.vo.SlogIllegalSiteVo;
import com.zx.idc.xml.entity.IllegalWeb;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.zx.idc.common.attributes.SystemAttributes.DF;

/**
 * Created by hasee on 2019/2/18.
 * 违法违规网站监测数据上报内容
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class IllegalWebServiceImpl implements IllegalWebService {
    private static final Logger LOG = LoggerFactory.getLogger(IllegalWebServiceImpl.class);

    @Autowired
    private ISlogIllegalSiteService iSlogIllegalSiteService;

    @Autowired
    private ISlogIllegalSiteLogService iSlogIllegalSiteLogService;

    @Autowired
    private IBaseHouseInfoService iBaseHouseInfoService;

    @Autowired
    private IBaseOperCompanyService iBaseOperCompanyService;

    @Autowired
    private NIdcFtpTemplate nIdcFtpTemplate;

    @Autowired
    private SlogIllegalSiteCacheService slogIllegalSiteCacheService;

    //属性字段
    private static final String COLUMN_ILLEGAL_SITE_ID = "illegalSiteId";
    private static final String COLUMN_ID = "id";


    /**
     * 主动上报逻辑
     */
    @Override
    public void illegalWebReport() {
        //获取所有idc的所有机房
        LOG.debug("Violation of laws and regulations website monitoring data report content start");
        List<BaseOperCompany> baseOperCompanies = iBaseOperCompanyService.selectList(new EntityWrapper<BaseOperCompany>().setSqlSelect("idcId"));
        if (baseOperCompanies == null || baseOperCompanies.isEmpty()) {
            LOG.debug("get Oper Company is empty,Violation of laws and regulations website monitoring data report content finish！");
            return;
        }
        List<IllegalWeb> illegalWebs = new ArrayList<>();

        //查出所有违法信息,装换为 ID->实体 的map
        List<SlogIllegalSite> slogIllegalSites = iSlogIllegalSiteService.listForAll();
        Map<Long, SlogIllegalSite> slogIllegalSiteMaps = slogIllegalSites.stream()
            .map(getCacheDateReplaceFunction()).collect(Collectors.toMap(SlogIllegalSite::getId, a -> a));
        try {
            //获取所有机房列表
            List<BaseHouseInfo> baseHouseInfos = iBaseHouseInfoService.listForAll();
            for (BaseHouseInfo baseHouseInfo : baseHouseInfos) {
                String idcId = baseHouseInfo.getIdcId();
                Long houseId = baseHouseInfo.getId();
                //查出未上报违法网站信息
                List<SlogIllegalSite> slogIllegalSitesOldData = iSlogIllegalSiteService.selectList(
                    new EntityWrapper<>(
                        new SlogIllegalSite()
                            .setHouseId(houseId)
                            .setReportStatus(ReportStatusConstant.NOT_REPORTED)
                    ).setSqlSelect(COLUMN_ID)
                );
                List<IllegalWeb> data;
                if (ListUtil.isEmpty(slogIllegalSitesOldData)) {
                    //零上报
                    LOG.debug("get zero data start！");
                    data = getZeroData(idcId, houseId);
                    LOG.debug("get zero data end！");

                } else {
                    LOG.debug("get SlogIllegalSiteLog data ...");
                    List<Long> SlogIllegalSiteIds = slogIllegalSitesOldData.stream().map(SlogIllegalSite::getId).collect(Collectors.toList());
                    //TODO 虽然这里是根据处置日志进行上传 但上传的数据不能体现处置的结果 意思是处置前/后数据都是一样的
                    List<SlogIllegalSiteLog> slogIllegalSiteLogs = iSlogIllegalSiteLogService.selectList(
                        new EntityWrapper<SlogIllegalSiteLog>()
                            .in(COLUMN_ILLEGAL_SITE_ID, SlogIllegalSiteIds)
                    );
                    data = slogIllegalSiteLogs.stream()
                        .map(obj -> slogIllegalSiteMaps.get(obj.getIllegalSiteId()))
                        .map(obj -> slogIllegalSite2IllegalWeb(idcId, obj))
                        .collect(Collectors.toList());
                    //没有数据则零上报
                    if (ListUtil.isEmpty(data)) {
                        LOG.debug("get SlogIllegalSiteLog data is empty,so get zero data");
                        data = getZeroData(idcId, houseId);
                    }
                }
                illegalWebs.addAll(data);

            }
        } catch (Exception e) {
            LOG.error("未知错误", e);
        }
        LOG.debug("report illegalWebs start");
        report(illegalWebs);
        LOG.debug("report illegalWebs done");
        LOG.debug("Violation of laws and regulations website monitoring data report content done");

    }

    /**
     * 数据替换 24小时访问量 从缓存里读出
     *
     * @return
     */
    private Function<SlogIllegalSite, SlogIllegalSite> getCacheDateReplaceFunction() {
        return (SlogIllegalSite slogIllegalSite) -> {
            IllegalSiteMetaInfo meta = slogIllegalSiteCacheService.getMeta(slogIllegalSite.getHouseId(), slogIllegalSite.getDomain());
            if (Objects.nonNull(meta)) {
                Optional.ofNullable(meta.getVisitCount()).ifPresent(slogIllegalSite::setVisitCount);
                Optional.ofNullable(meta.getLastFound()).ifPresent(lastFound ->
                    slogIllegalSite.setLastFound(LocalDateTimeFormatUtil.formatLocalDateTime(lastFound))
                );
            }
            return slogIllegalSite;
        };
    }

    @Override
    public void illegalWebReport(HandleEntity<SlogIllegalSiteVo> handleEntity) {
        //按houseID分组
        Set<Long> houseIdSet = new HashSet<>();
        Map<Long, List<SlogIllegalSite>> dataMap = new HashMap<>();
        List<SlogIllegalSite> datas = handleEntity.getData().stream().map(getCacheDateReplaceFunction()).collect(Collectors.toList());
        for (SlogIllegalSite slogIllegalSiteVo : datas) {
            //根据houseId获取IDCID
            Long houseId = slogIllegalSiteVo.getHouseId();
            houseIdSet.add(houseId);
            //根据houseId分组
            List<SlogIllegalSite> slogIllegalSiteVos = dataMap.get(houseId);
            if (slogIllegalSiteVos == null) {
                dataMap.put(houseId, Lists.newArrayList(slogIllegalSiteVo));
            } else {
                slogIllegalSiteVos.add(slogIllegalSiteVo);
            }

        }
        //获取机房的idcId
        List<BaseHouseInfo> baseHouseInfosOld = iBaseHouseInfoService.selectList(
            new EntityWrapper<BaseHouseInfo>()
                .in(COLUMN_ID, houseIdSet)
                .setSqlSelect("idcId")
        );
        //获取idcId下的所有机房
        Set<String> idcIdSet = baseHouseInfosOld.stream().map(BaseHouseInfo::getIdcId).collect(Collectors.toSet());
        List<BaseHouseInfo> baseHouseInfos = iBaseHouseInfoService.selectList(
            new EntityWrapper<BaseHouseInfo>()
                .in("idcId", idcIdSet)
        );

        List<IllegalWeb> illegalWebs = new ArrayList<>();

        for (BaseHouseInfo baseHouseInfo : baseHouseInfos) {
            Long houseId = baseHouseInfo.getId();
            String idcId = baseHouseInfo.getIdcId();
            List<IllegalWeb> data;
            //进行零上报
            List<SlogIllegalSite> slogIllegalSites = dataMap.get(houseId);
            if (slogIllegalSites == null) {
                data = getZeroData(idcId, houseId);
            } else {
                data = slogIllegalSites.stream()
                    .map(obj -> slogIllegalSite2IllegalWeb(idcId, obj))
                    .collect(Collectors.toList());
            }
            illegalWebs.addAll(data);
        }

        report(illegalWebs);
    }

    /**
     * 零上报数据
     *
     * @return
     */
    private List<IllegalWeb> getZeroData(String idcId, Long houseId) {

        return Lists.newArrayList(
            new IllegalWeb()
                .setIdcId(idcId)
                .setHouseId(houseId)
                .setVisitCount(0)
                .setBlock(0)
                .setDomain("0")
                .setFirstFound("0")
                .setIllegalType(0)
                .setIp("0")
                .setLastFound("0")
                .setOperationAccount("0")
                .setPort(0L)
                .setProtocol(0)
                .setServiceContent(Lists.newArrayList(0))
        );
    }

    /**
     * 实体装换
     *
     * @param idcId
     * @param slogIllegalSite
     * @return
     */
    private IllegalWeb slogIllegalSite2IllegalWeb(String idcId, SlogIllegalSite slogIllegalSite) {
        List<Integer> serviceContent = Lists.newArrayList(slogIllegalSite.getServiceContent().split(","))
            .stream().map(Integer::valueOf).collect(Collectors.toList());
        return new IllegalWeb()
            .setIdcId(idcId)
            .setHouseId(slogIllegalSite.getHouseId())
            .setVisitCount(slogIllegalSite.getVisitCount())
            .setBlock(slogIllegalSite.getBlock())
            .setDomain(slogIllegalSite.getDomain())
            .setFirstFound(DF.format(slogIllegalSite.getFirstFound()))
            .setIllegalType(slogIllegalSite.getIllegalType())
            .setIp(slogIllegalSite.getIp())
            .setLastFound(DF.format(slogIllegalSite.getLastFound()))
            .setOperationAccount(slogIllegalSite.getOperationAccount())
            .setPort(slogIllegalSite.getPort())
            .setProtocol(slogIllegalSite.getProtocol())
            .setServiceContent(serviceContent);
    }

    /**
     * 上报的公共代码
     *
     * @param illegalWebs
     */
    private void report(List<IllegalWeb> illegalWebs) {
        //主动上报
        for (IllegalWeb illegalWeb : illegalWebs) {
            //修改上报状态为 上报中
            updateReportStatus(illegalWeb, ReportStatusConstant.REPORTING);
            nIdcFtpTemplate.uploadXMLFile(
                new UploadModel<>(
                    illegalWeb,
                    SchemaFileNameEnum.ILLEGAL_WEBSITE_MONITOR_DATA,
                    FTPReportDataTypeEnum.FTP_VIOLATION_WEBSITE_MONITORING_RECORD,
                    NetCommunicationFileTypeEnum.VIOLATION_MONITOR
                )
            );
        }
    }

    /**
     * 更新上报状态 违法信息和违法处置信息
     * @param illegalWeb
     */
    private void updateReportStatus(IllegalWeb illegalWeb, Integer reportStatus) {
        SlogIllegalSite slogIllegalSite = iSlogIllegalSiteService.selectFirst(
            new EntityWrapper<>(
                new SlogIllegalSite()
                    .setDomain(illegalWeb.getDomain())
            ).setSqlSelect(COLUMN_ID)
        );
        iSlogIllegalSiteService.update(
            new SlogIllegalSite().setReportStatus(reportStatus),
            new EntityWrapper<>(
                new SlogIllegalSite().setDomain(illegalWeb.getDomain())
            )
        );
        if (slogIllegalSite != null && slogIllegalSite.getId() != null) {
            iSlogIllegalSiteLogService.update(
                new SlogIllegalSiteLog().setReportStatus(reportStatus),
                new EntityWrapper<>(
                    new SlogIllegalSiteLog().setIllegalSiteId(slogIllegalSite.getId())
                )
            );
        }
    }
}
